在有關Web方面我們常常會使用多執行緒以及非同布方法
儘管已經接觸一段時間
對於race conditon的處理還不是很嫻熟
本篇只會講解比較基本的多緒概念
會著重在如何使用多緒
建議若是想要深入程式設計這塊
可以去研讀下作業系統
執行緒是作業系統分配CPU的最小單位
他們共享同個程式的一些共有變數
(上面是OS的敘述)
在C#內依行為來區分執行緒可分為兩種:
前景執行緒和背景執行緒
兩者的主要區別是:當所有的前景執行緒停止時,應用程式就會結束,並且停止所有背景執行緒。
若只是停止背景執行緒,則不會造成應用程式結束。
** 簡單來說執行緒就是一個附生在主程式的程式 他會做你指派給他的工作**
請引用命名空間System.Threading
using System.Threading
來看個範例
using System;
using System.Threading;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
Thread thread = new Thread(Run);//指派工作給執行緒
thread.Start();//使用thread.Start(); 來開始執行緒工作
while (true)
{
Console.WriteLine("防守!防守!");
Thread.Sleep(500);
//使用Tread.Sleep()讓執行緒暫時停止工作 單位為毫秒
}
}
static void Run()
{
while (true)
{
Console.WriteLine("執行緒大軍進攻拉");
Thread.Sleep(1000);
}
}
}
}
假設我們有一個訂票網站
使用者A跟使用者B今天都想要訂同一場演唱會的門票
但是座位只剩下一個
A跟B剛好在同一時間打開網站
A看見還有位置就下了訂單
B也看到還有位置也下了單
但是系統沒有針對這個位置做處理
最後A只能坐在B的大腿上
主辦單位賺兩分錢 可喜可賀(X
上面的問題是設計購物網站常出現的問題
我們再來看看貼近我們這章要講的執行緒的例子吧
我們有一個共享變數v
初值為5
public static int v = 5;
執行緒A做的事是把v+1
static void RunA()
{
v = v + 1;
}
執行緒B做的事是把v-1
static void RunB()
{
v = v - 1;
}
void Main(){
Thread A = new Thread(RunA);
Thread B = new Thread(RunB);
A.Start();
B.Start();
Console.WriteLine(v);
}
上面v上看下看左看右看 都是5
實際上v 會有可能有4 5 6
3種答案
v = v + 1; // v = 6
v = v - 1; // v = 5
v = 5
其實上面的狀況能拆成4個步驟
step | action |
---|---|
1 | Thread a 執行 v + 1 |
2 | Thread a 將v + 1 的值 assign給 v |
3 | Thread b 執行 v - 1 |
4 | Thread b 將v + - 的值 assign給 v |
如果今天按照1324的步驟執行 那麼v就會變成 4
按照3142的步驟 v 會等於6
這種情況我們就稱為競爭條件(race condtion)
或是同步問題
可以使用lock
我們先宣告一個共用的物件object(因為int型態不能鎖)
public static object lockObj;
改寫下RunA跟RunB
static void RunA()
{
lock(lockObj){
v = v + 1;
}
}
static void RunB()
{
lock(lockObj){
v = v - 1;
}
}
這樣子在被lock{}中的程式碼就成為中華民國不可分割的領土了不能分割的運算式了
優先搶到lockObj的人能夠先執行運算式
直到執行完會釋放lockObj
因為lockObj只有一份
所以同一時間只為有一個人搶到
我們稱沒有同步問題的咚咚為執行緒安全(Thread safety)
容易因為忘記釋放或是設計不量導致死結(DeadLock)( http://ccckmit.wikidot.com/cs-deadlock )
我們在[Day6] 今晚我想來點基礎的資料結構中有提到
3種資料結構 Stack Queue 跟 Dictionary
事實上它們都不是執行緒安全的結構
也就是今天兩個執行緒興高采烈要到同一個Queue裡面拿東西時
A先把東西拿走了
B沒有發現A把東西拿走了
所以B也傻傻地去Queue裡面拿東西
好死不死那是最後一個
B就會出例外
因此在需要考慮執行緒安全的結構可以使用
ConccurentQueue ConcurrentDictionary 跟 ConcurrentStack
用法跟原本的很像
只是取出變成要try
詳閱Dequeue
我覺得這部分官方的教學做的很棒
有圖片輔助學習
所以麻煩大家花個5分鐘看看官方文件
使用 async 和 await 進行非同步程式設計
今天也不知不覺第10天了越來越沒有動力
這邊一些基礎跟進階的語法都講得差不多了
接下來才是我原本想起頭的地方
原本只是因為怕30天塞不滿
結果根本是想太多了RRR